package klog

import (
	"sync"
	"sync/atomic"
)

type Stat struct {
	CurRetried      int64
	DownSampledLogs int64 // 被降采样丢弃的日志数
	DroppedLogs     int64 // 因日志池不存在，被丢弃的日志数
	ErroredLogs     int64 // 单条超限或编码错误，被丢弃的日志数
	FailedBatches   int64
	FailedLogs      int64 // 达到最大重试次数之后，被丢弃的日志数
	LastError       string
	LastLogs        int64
	LastRetried     int64
	LastRetriedAt   string
	LastSucceededAt string
	Retried         int64
	SentBatches     int64
	SentLogs        int64 // 发送成功的日志数
	StartedAt       string

	lock     *sync.Mutex
	lastStat *Stat
}

func newStat() *Stat {
	return &Stat{
		lock:     new(sync.Mutex),
		lastStat: new(Stat),
	}
}

func (o *Stat) setCurRetried(n int)         { atomic.StoreInt64(&o.CurRetried, int64(n)) }
func (o *Stat) addDownSampledLogs(n int)    { atomic.AddInt64(&o.DownSampledLogs, int64(n)) }
func (o *Stat) addDroppedLogs(n int)        { atomic.AddInt64(&o.DroppedLogs, int64(n)) }
func (o *Stat) addErroredLogs(n int)        { atomic.AddInt64(&o.ErroredLogs, int64(n)) }
func (o *Stat) addFailedBatches(n int)      { atomic.AddInt64(&o.FailedBatches, int64(n)) }
func (o *Stat) addFailedLogs(n int)         { atomic.AddInt64(&o.FailedLogs, int64(n)) }
func (o *Stat) setLastError(e string)       { o.LastError = e }
func (o *Stat) setLastLogs(n int)           { atomic.StoreInt64(&o.LastLogs, int64(n)) }
func (o *Stat) setLastRetried(n int)        { atomic.StoreInt64(&o.LastRetried, int64(n)) }
func (o *Stat) setLastRetriedAt(e string)   { o.LastRetriedAt = e }
func (o *Stat) setLastSucceededAt(e string) { o.LastSucceededAt = e }
func (o *Stat) addRetried(n int)            { atomic.AddInt64(&o.Retried, int64(n)) }
func (o *Stat) addSentBatches(n int)        { atomic.AddInt64(&o.SentBatches, int64(n)) }
func (o *Stat) addSentLogs(n int)           { atomic.AddInt64(&o.SentLogs, int64(n)) }
func (o *Stat) setStartedAt(e string)       { o.StartedAt = e }

func (o *Stat) getCurrent() *Stat {
	return &Stat{
		CurRetried:      atomic.LoadInt64(&o.CurRetried),
		DownSampledLogs: atomic.LoadInt64(&o.DownSampledLogs),
		DroppedLogs:     atomic.LoadInt64(&o.DroppedLogs),
		ErroredLogs:     atomic.LoadInt64(&o.ErroredLogs),
		FailedBatches:   atomic.LoadInt64(&o.FailedBatches),
		FailedLogs:      atomic.LoadInt64(&o.FailedLogs),
		LastError:       o.LastError,
		LastLogs:        atomic.LoadInt64(&o.LastLogs),
		LastRetried:     atomic.LoadInt64(&o.LastRetried),
		LastRetriedAt:   o.LastRetriedAt,
		LastSucceededAt: o.LastSucceededAt,
		Retried:         atomic.LoadInt64(&o.Retried),
		SentBatches:     atomic.LoadInt64(&o.SentBatches),
		SentLogs:        atomic.LoadInt64(&o.SentLogs),
		StartedAt:       o.StartedAt,
	}
}

func (o *Stat) getDelta() *Stat {
	o.lock.Lock()
	defer o.lock.Unlock()
	cur := o.getCurrent()
	d := &Stat{
		CurRetried:      cur.CurRetried,
		DownSampledLogs: cur.DownSampledLogs - o.lastStat.DownSampledLogs,
		DroppedLogs:     cur.DroppedLogs - o.lastStat.DroppedLogs,
		ErroredLogs:     cur.ErroredLogs - o.lastStat.ErroredLogs,
		FailedBatches:   cur.FailedBatches - o.lastStat.FailedBatches,
		FailedLogs:      cur.FailedLogs - o.lastStat.FailedLogs,
		LastError:       o.LastError,
		LastLogs:        cur.LastLogs - o.lastStat.LastLogs,
		LastRetried:     cur.LastRetried - o.lastStat.LastRetried,
		LastRetriedAt:   o.LastRetriedAt,
		LastSucceededAt: o.LastSucceededAt,
		Retried:         cur.Retried - o.lastStat.Retried,
		SentBatches:     cur.SentBatches - o.lastStat.SentBatches,
		SentLogs:        cur.SentLogs - o.lastStat.SentLogs,
		StartedAt:       o.StartedAt,
	}
	o.lastStat = cur
	return d
}
